﻿#region File Description
//-----------------------------------------------------------------------------
// DeferedContinueWithTask
//
// Copyright © 2013 Wave Coorporation. All rights reserved.
// Use is subject to license terms.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Diagnostics;
using WaveEngine.Framework;
#endregion

namespace WaveEngine.Extensions.ITasks
{

    public abstract class DeferedTaskNodeBase : TaskBase
    {
        /// <summary>
        /// The running task
        /// </summary>
        protected ITask runningTask;

        /// <summary>
        /// Initializes a new instance of the <see cref="DeferedTaskNodeBase" /> class.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="taskName">Name of the task.</param>
        protected DeferedTaskNodeBase(ITask parent, string taskName)
            : base(parent, taskName)
        {

        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DeferedTaskNodeBase" /> class.
        /// </summary>
        /// <param name="scene">The scene.</param>
        protected DeferedTaskNodeBase(Scene scene)
            : base(scene, null)
        {
        }


        /// <summary>
        /// Internals the task cancelled.
        /// </summary>
        private void internalTaskCancelled()
        {
            this.runningTask.Cancel();
            base.performCancel();
            runningTask.Completed -= internalTaskCompleted;
            //runningTask.Cancelled -= internalTaskCancelled;
        }

        /// <summary>
        /// Internals the task completed.
        /// </summary>
        private void internalTaskCompleted()
        {
            this.performCompleted();
            runningTask.Completed -= internalTaskCompleted;
            //runningTask.Cancelled -= internalTaskCancelled;
        }
                       
        /// <summary>
        /// Ons the run.
        /// </summary>
        [DebuggerStepThrough]
        protected override void performRun()
        {
            generateAndStoreTask();
            if (runningTask.TaskState == WaveEngine.Framework.Services.TaskState.None
                || runningTask.TaskState == WaveEngine.Framework.Services.TaskState.Waiting)
            {
                /*
                if (runningTask is IRunableTask)
                    ((IRunableTask)runningTask).Run();
                else
                    throw new InvalidOperationException("The task should be runing, finished or cancelled at this momment. None is not allowed");
                 * */
                runningTask.Completed += internalTaskCompleted;
                //runningTask.Cancelled += internalTaskCancelled;
                runningTask.Run();
            }
            else if (runningTask.TaskState == WaveEngine.Framework.Services.TaskState.Running)
            {
                runningTask.Completed += internalTaskCompleted;
                //runningTask.Cancelled += internalTaskCancelled;
            }
            else
            {
                throw new NotSupportedException("Task cannot be launched if the state is Aborted or Finished");
            }
        }

        /// <summary>
        /// Notifies the skip.
        /// </summary>
        protected override bool performSkip()
        {
            if (this.IsSkippable)
            {
                if (this.runningTask.TaskState == WaveEngine.Framework.Services.TaskState.Running)
                    runningTask.Cancel();

                base.performSkip();
                return true;
            }
            else
            {
                return this.runningTask.TrySkip();
            }
        }

        /// <summary>
        /// Notifies the cancelled.
        /// </summary>
        protected override void performCancel()
        {
            if (this.TaskState == WaveEngine.Framework.Services.TaskState.Running)
                this.runningTask.Cancel();

            base.performCancel();
        }

        /// <summary>
        /// Generates the and store task.
        /// </summary>
        protected abstract void generateAndStoreTask();

        /// <summary>
        /// Gets or sets the child tasks.
        /// </summary>
        /// <value>
        /// The child tasks.
        /// </value>
        /// <exception cref="System.NotImplementedException"></exception>
        public override IEnumerable<ITask> ChildTasks
        {
            get
            {
                if (this.runningTask != null)
                    yield return runningTask;
            }
        }
    }   

    public class DeferedTaskNode : DeferedTaskNodeBase
    {
        private Func<ITask> nextTask;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="DeferedTaskNode" /> class.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="taskName">Name of the task.</param>
        /// <param name="nextTask">The next task.</param>
        internal DeferedTaskNode(ITask parent, string taskName, Func<ITask> nextTask)
            : base(parent, taskName)
        {
            this.nextTask = nextTask;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DeferedTaskNode" /> class.
        /// </summary>
        /// <param name="scene">The scene.</param>
        /// <param name="nextTask">The next task.</param>
        internal DeferedTaskNode(Scene scene, Func<ITask> nextTask)
            : base(scene)
        {
            this.nextTask = nextTask;
        }

        /// <summary>
        /// Generates the and store task.
        /// </summary>
        [DebuggerStepThrough]
        protected override void generateAndStoreTask()
        {
            runningTask = nextTask();
        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return base.ToString() + "-> task: " + nextTask.ToString();
        }
    }

    internal class DeferedContinueWithTask<TResult> : DeferedTaskNodeBase
    {
        private Func<TResult, ITask> nextTask;
        ITask<TResult> parent;
        internal DeferedContinueWithTask(ITask<TResult> parent, string taskName, Func<TResult, ITask> nextTask)
            : base(parent, string.Empty)
        {
            this.parent = parent;
            this.nextTask = nextTask;
        }

        /// <summary>
        /// Generates the and store task.
        /// </summary>
        protected override void generateAndStoreTask()
        {
            runningTask = this.nextTask(parent.Result);
        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return base.ToString() + "-> task: " + nextTask.ToString();
        }
    }
}
